﻿/* 
 * yaku
 * http://code.google.com/p/yaku/
 * 
 * Copyright 2011, Bryan McKelvey
 * Licensed under the MIT license
 * http://www.opensource.org/licenses/mit-license.php
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace yaku
{
    /// <summary>
    /// A class for romanizing Japanese.
    /// </summary>
    public static partial class Transliterator
    {
        private enum CharacterType { Normal, Vowel, SmallVowel, LargeY, SmallY, SmallTsu };
        private static JapaneseTransliteration[] intermediates;
        private static EnglishTransliteration[] hepburn;
        private const string defaultSeparator = ", ";

        /// <summary>
        /// Builds the collection of transliteration objects for use.
        /// </summary>
        public static void Build()
        {
            #region Intermediates
            intermediates = new JapaneseTransliteration[]{
                    new JapaneseTransliteration('ー', 'ー', "-"),
                    new JapaneseTransliteration('あ', 'ア', "?a"),
                    new JapaneseTransliteration('い', 'イ', "?i"),
                    new JapaneseTransliteration('う', 'ウ', "?u"),
                    new JapaneseTransliteration('え', 'エ', "?e"),
                    new JapaneseTransliteration('お', 'オ', "?o"),
                    new JapaneseTransliteration('ぁ', 'ァ', "xa"),
                    new JapaneseTransliteration('ぃ', 'ィ', "xi"),
                    new JapaneseTransliteration('ぅ', 'ゥ', "xu"),
                    new JapaneseTransliteration('ぇ', 'ェ', "xe"),
                    new JapaneseTransliteration('ぉ', 'ォ', "xo"),
                    new JapaneseTransliteration('か', 'カ', "ka"),
                    new JapaneseTransliteration('き', 'キ', "ki"),
                    new JapaneseTransliteration('く', 'ク', "ku"),
                    new JapaneseTransliteration('け', 'ケ', "ke"),
                    new JapaneseTransliteration('こ', 'コ', "ko"),
                    new JapaneseTransliteration('が', 'ガ', "ga"),
                    new JapaneseTransliteration('ぎ', 'ギ', "gi"),
                    new JapaneseTransliteration('ぐ', 'グ', "gu"),
                    new JapaneseTransliteration('げ', 'ゲ', "ge"),
                    new JapaneseTransliteration('ご', 'ゴ', "go"),
                    new JapaneseTransliteration('さ', 'サ', "sa"),
                    new JapaneseTransliteration('し', 'シ', "si"),
                    new JapaneseTransliteration('す', 'ス', "su"),
                    new JapaneseTransliteration('せ', 'セ', "se"),
                    new JapaneseTransliteration('そ', 'ソ', "so"),
                    new JapaneseTransliteration('ざ', 'ザ', "za"),
                    new JapaneseTransliteration('じ', 'ジ', "ji"),
                    new JapaneseTransliteration('ず', 'ズ', "zu"),
                    new JapaneseTransliteration('ぜ', 'ゼ', "ze"),
                    new JapaneseTransliteration('ぞ', 'ゾ', "zo"),
                    new JapaneseTransliteration('た', 'タ', "ta"),
                    new JapaneseTransliteration('ち', 'チ', "ti"),
                    new JapaneseTransliteration('つ', 'ツ', "tu"),
                    new JapaneseTransliteration('て', 'テ', "te"),
                    new JapaneseTransliteration('と', 'ト', "to"),
                    new JapaneseTransliteration('だ', 'ダ', "da"),
                    new JapaneseTransliteration('ぢ', 'ヂ', "di"),
                    new JapaneseTransliteration('づ', 'ヅ', "du"),
                    new JapaneseTransliteration('で', 'デ', "de"),
                    new JapaneseTransliteration('ど', 'ド', "do"),
                    new JapaneseTransliteration('な', 'ナ', "na"),
                    new JapaneseTransliteration('に', 'ニ', "ni"),
                    new JapaneseTransliteration('ぬ', 'ヌ', "nu"),
                    new JapaneseTransliteration('ね', 'ネ', "ne"),
                    new JapaneseTransliteration('の', 'ノ', "no"),
                    new JapaneseTransliteration('は', 'ハ', "ha"),
                    new JapaneseTransliteration('ひ', 'ヒ', "hi"),
                    new JapaneseTransliteration('ふ', 'フ', "hu"),
                    new JapaneseTransliteration('へ', 'ヘ', "he"),
                    new JapaneseTransliteration('ほ', 'ホ', "ho"),
                    new JapaneseTransliteration('ば', 'バ', "ba"),
                    new JapaneseTransliteration('び', 'ビ', "bi"),
                    new JapaneseTransliteration('ぶ', 'ブ', "bu"),
                    new JapaneseTransliteration('べ', 'ベ', "be"),
                    new JapaneseTransliteration('ぼ', 'ボ', "bo"),
                    new JapaneseTransliteration('ぱ', 'パ', "pa"),
                    new JapaneseTransliteration('ぴ', 'ピ', "pi"),
                    new JapaneseTransliteration('ぷ', 'プ', "pu"),
                    new JapaneseTransliteration('ぺ', 'ペ', "pe"),
                    new JapaneseTransliteration('ぽ', 'ポ', "po"),
                    new JapaneseTransliteration('ま', 'マ', "ma"),
                    new JapaneseTransliteration('み', 'ミ', "mi"),
                    new JapaneseTransliteration('む', 'ム', "mu"),
                    new JapaneseTransliteration('め', 'メ', "me"),
                    new JapaneseTransliteration('も', 'モ', "mo"),
                    new JapaneseTransliteration('や', 'ヤ', "ya"),
                    new JapaneseTransliteration('ゆ', 'ユ', "yu"),
                    new JapaneseTransliteration('よ', 'ヨ', "yo"),
                    new JapaneseTransliteration('ゃ', 'ャ', "xya"),
                    new JapaneseTransliteration('ゅ', 'ュ', "xyu"),
                    new JapaneseTransliteration('ょ', 'ョ', "xyo"),
                    new JapaneseTransliteration('ら', 'ラ', "ra"),
                    new JapaneseTransliteration('り', 'リ', "ri"),
                    new JapaneseTransliteration('る', 'ル', "ru"),
                    new JapaneseTransliteration('れ', 'レ', "re"),
                    new JapaneseTransliteration('ろ', 'ロ', "ro"),
                    new JapaneseTransliteration('わ', 'ワ', "wa"),
                    new JapaneseTransliteration('を', 'ヲ', "wo"),
                    new JapaneseTransliteration('ん', 'ン', "N"),
                    new JapaneseTransliteration('っ', 'ッ', "xtu")
                };
            #endregion

            #region Hepburn
            hepburn = new EnglishTransliteration[]
                {
                    new EnglishTransliteration("N'", "n?"),
                    new EnglishTransliteration("N", "n"),
                    new EnglishTransliteration("si", "shi"),
                    new EnglishTransliteration("zi", "ji"),
                    new EnglishTransliteration("ti", "chi"),
                    new EnglishTransliteration("di", "ji"),
                    new EnglishTransliteration("ixy", "y"),
                    new EnglishTransliteration("shy", "sh"),
                    new EnglishTransliteration("jy", "j"),
                    new EnglishTransliteration("chy", "ch"),
                    new EnglishTransliteration("tu", "tsu"),
                    new EnglishTransliteration("du", "zu"),
                    new EnglishTransliteration("hu", "fu"),
                    new EnglishTransliteration("xtsuk", "kk"),
                    new EnglishTransliteration("xtsug", "gg"),
                    new EnglishTransliteration("xtsus", "ss"),
                    new EnglishTransliteration("xtsuz", "dz"),
                    new EnglishTransliteration("xtsuj", "dj"),
                    new EnglishTransliteration("xtsut", "tt"),
                    new EnglishTransliteration("xtsuch", "tch"),
                    new EnglishTransliteration("xtsud", "dd"),
                    new EnglishTransliteration("xtsuh", "hh"),
                    new EnglishTransliteration("xtsub", "bb"),
                    new EnglishTransliteration("xtsup", "pp"),
                    new EnglishTransliteration("a?a", "ā"),
                    new EnglishTransliteration("e?e", "ē"),
                    new EnglishTransliteration("i?i", "ī"),
                    new EnglishTransliteration("o?o", "ō"),
                    new EnglishTransliteration("o?u", "ō"),
                    new EnglishTransliteration("u?u", "ū"),
                    new EnglishTransliteration("a-", "ā"),
                    new EnglishTransliteration("e-", "ē"),
                    new EnglishTransliteration("i-", "ī"),
                    new EnglishTransliteration("o-", "ō"),
                    new EnglishTransliteration("u-", "ū"),
                    new EnglishTransliteration("?", "")
                };
            #endregion
        }

        /// <summary>
        /// Transliterates a string according to the rules of Hepburn romanization.
        /// </summary>
        /// <param name="input">The string to transliterate.</param>
        /// <returns>The transliterated string.</returns>
        public static string Romanize(string input)
        {
            StringBuilder builder = new StringBuilder();
            string output;

            // Transliterate from Japanese to intermediate romanization
            foreach (char kana in input)
            {
                foreach (JapaneseTransliteration transliteration in intermediates)
                {
                    if (transliteration.Hiragana == kana || transliteration.Katakana == kana)
                    {
                        builder.Append(transliteration.Intermediate);
                    }
                }
            }

            output = builder.ToString();

            // Transliterate from intermediate romanization to final romanization
            foreach (EnglishTransliteration transliteration in hepburn)
            {
                output = output.Replace(transliteration.Intermediate, transliteration.Final);
            }

            return output;
        }

        #region Romanize overrides
        /// <summary>
        /// Transliterates an array of strings, separated by ", ", according to the rules of Hepburn romanization.
        /// </summary>
        /// <param name="inputs">An array that contains the strings to transliterate.</param>
        /// <returns>The transliterated string.</returns>
        public static string Romanize(string[] inputs)
        {
            return Romanize(inputs.ToList(), defaultSeparator);
        }

        /// <summary>
        /// Transliterates an array of strings according to the rules of Hepburn romanization.
        /// </summary>
        /// <param name="inputs">An array that contains the strings to transliterate.</param>
        /// <param name="separator">The string to use as a separator. Defaults to ", ".</param>
        /// <returns>The transliterated string.</returns>
        public static string Romanize(string[] inputs, string separator)
        {
            return Romanize(inputs.ToList(), separator);
        }

        /// <summary>
        /// Transliterates an array of strings, separated by ", ", according to the rules of Hepburn romanization.
        /// </summary>
        /// <param name="inputs">A list that contains the strings to transliterate.</param>
        /// <returns>The transliterated string.</returns>
        public static string Romanize(List<string> inputs)
        {
            return Romanize(inputs, defaultSeparator);
        }

        /// <summary>
        /// Transliterates an array of strings according to the rules of Hepburn romanization.
        /// </summary>
        /// <param name="inputs">A list that contains the strings to transliterate.</param>
        /// <param name="separator">The string to use as a separator. Defaults to ", ".</param>
        /// <returns>The transliterated string.</returns>
        public static string Romanize(List<string> inputs, string separator)
        {
            string tempSeparator = "";
            StringBuilder builder = new StringBuilder();
            foreach (string input in inputs)
            {
                builder.Append(tempSeparator).Append(Romanize(input));
                if (tempSeparator == "")
                {
                    tempSeparator = separator;
                }
            }
            return builder.ToString();
        }
        #endregion
    }
}